type EventFunc = (e: Event) => void;
type MsgFunc = (e: MessageEvent) => void;
type CloseFunc = (e: CloseEvent) => void;

export interface IWSEvent {
    onOpen: EventFunc,
    onError: EventFunc,
    onMessage: MsgFunc,
    onClose: CloseFunc,
}

export interface IWSClient {
    url: string,
    onOpen?: EventFunc,
    onError?: EventFunc,
    onMessage?: MsgFunc,
    onClose?: CloseFunc,
}

export default class WSClient {
    conn: WebSocket = null!;
    param: IWSClient = null!;
    isConnect = false;
    connect(param: IWSClient) {
        this.param = param;
        const conn = new WebSocket(param.url);
        conn.onopen = this._onOpen.bind(this);
        conn.onclose = this._onClose.bind(this);
        conn.onerror = this._onError.bind(this);
        conn.onmessage = this._onMessage.bind(this);
        conn.binaryType = 'arraybuffer';
        this.conn = conn;
        return conn;
    }

    send(msgId: number, data: ArrayBuffer) {
        if (!this.conn || this.conn.readyState != this.conn.OPEN) {
            console.error("send failed, ws is not connet", msgId);
            return false;
        }
        this.conn.send(data);
        return true;
    }

    close() {
        if (this.isConnect) {
            this.isConnect = false
            this.conn.close();
        }
    }

    private _onOpen(e: Event) {
        this.isConnect = true;
        this.param.onOpen && this.param.onOpen(e);
        console.log(`websocket connected success`, this.param.url);
    }

    private _onError(e: Event) {
        this.isConnect = false;
        this.param.onError && this.param.onError(e);
        console.error(`websocket error`, e);
    }

    private _onClose(e: CloseEvent) {
        this.isConnect = false;
        this.param.onClose && this.param.onClose(e);
        console.error(`websocket close`, e);
    }

    private _onMessage(e: MessageEvent<any>) {
        this.param.onMessage && this.param.onMessage(e);
    }
}
